<template>
  <div>
    <el-form
        :model="formData"
        ref="form"
        :label-width="computedLabelWidth"
        :label-position="propsRef.labelPosition"
        :validate-on-rule-change="false"
        v-bind="formAttrs"
    >
      <!-- 默认插槽作为表单项 -->
      <slot/>
      <el-row :gutter="20">
        <template v-for="(formItem, field) of formDesc" :key="field">
          <el-col
              :span="span"
              v-show="fieldsKeysMap[field]"
          >
            <el-form-item
                :label="formItem.label || ''"
                :label-width="formItem.labelWidth || 'auto'"
                :prop="field"
            >
              <slot
                  :data="formData[field]"
                  :desc="formItem"
                  :props="$props"
                  :field="field"
                  :formData="formData"
                  :name="field"
                  :disabled="formItem.disabled"
                  :type="formItem.type"
                  :options="formItem.options"
              >
                <el-input
                    :placeholder="`请输入${formItem.label}`"
                    v-model="formData[field]"
                    style="width: 100%"
                    v-if="formItem.type === 'input'"
                    v-bind="formItem.attrs"/>
                <el-input-number
                    :placeholder="`请输入${formItem.label}`"
                    v-model="formData[field]"
                    style="width: 100%"
                   v-if="formItem.type === 'number'"
                    v-bind="formItem.attrs"/>
                <el-select
                    :placeholder="`请选择${formItem.label}`"
                    v-model="formData[field]"
                    style="width: 100%;"
                    v-if="formItem.type === 'select'"
                    v-bind="formItem.attrs"
                    filterable
                    :filter-method="q => (query = q)">
                  <el-option
                      v-for="item in optionsComputed(formItem.options)"
                      :key="item.value"
                      :value="item.value"
                      :label="item.label">
                    <div v-html="item.highlight"></div>
                  </el-option>
                </el-select>
                <el-date-picker
                    :placeholder="`请输入${formItem.label}`"
                    v-model="formData[field]"
                    style="width: 100%"
                    v-if="['year','month','date','dates','datetime','week','datetimerange','daterange', 'monthrange'].includes(formItem.type)"
                    v-bind="formItem.attrs"/>
              </slot>
            </el-form-item>
          </el-col>
        </template>
        <el-col :span="8">
          <el-button @click="handleSearch" type="primary" icon="Search">搜索</el-button>
          <el-button @click="checkDefault" icon="Refresh">重置</el-button>
          <!-- el-icon-arrow-up -->
          <span style="margin-left: 2%" @click="openAdv = !openAdv">
            <el-button v-show="isShow" type="primary" link >{{ openAdv ? '收缩' : '展开' }}
              <el-icon color="#409EFF">
                <ArrowUp v-if="openAdv"/>
                <ArrowDown v-else/>
              </el-icon>
            </el-button>
          </span>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import { filterMap } from 'sdm2';
import {ref, toRefs, computed, onMounted} from "vue";

const props = defineProps({
  span: {
    type: Number,
    default: 8,
  },
  labelPosition: String,
  labelWidth: {
    type: [Number, String],
    default: "auto",
  },
  // 表单数据
  formData: {
    type: Object,
    required: true,
  },
  formDesc: {
    type: Object,
    required: true,
  },
  // 表单自身属性
  formAttrs: Object,
})

const propsRef = toRefs(props)

const form = ref()
const { formDesc,formData,span } = propsRef
const fieldsKeysMap = ref<any>({})
// 是否展示展开收缩按钮
const isShow = computed(() => {
  const fieldsKeys = Object.keys(formDesc.value)
  const max = 24 / span.value
  const obj:any  = {}
  fieldsKeys.forEach((i,index)=>{
    obj[i] = index+1 >= max ? openAdv : true
  })
  fieldsKeysMap.value = obj
  return fieldsKeys.length >= max
})
const openAdv = ref<boolean>(false)
const computedLabelWidth = () => {
  if (typeof propsRef.labelWidth.value === 'number') {
    return propsRef.labelWidth.value + "px";
  } else {
    return propsRef.labelWidth.value;
  }
}
//检测默认值 | 重置
const checkDefault = () => {
  form.value.resetFields()
  for (const field in formDesc.value) {
    if (formDesc.value.hasOwnProperty('default')) {
      formData.value[field] = formDesc.value.default
    } else {
      formData.value[field] = null
    }
  }
  handleSearch()
}
//获取选择框options
const getOptions = async () => {
  for (const field in formDesc.value) {
    if (formDesc.value[field].dicUrl) {
      const res = await formDesc.value[field].dicUrl()
      formDesc.value[field].options = ((res.data.result && Array.isArray(res.data.result)
          || res.data.result.records && Array.isArray(res.data.result.records)) || []).map((i:any) => {
        if (formDesc.value[field].props) {
          return {
            label: i[formDesc.value[field].props.label],
            value: i[formDesc.value[field].props.value]
          }
        } else {
          return {...i}
        }
      })
    }
  }
}

const query = ref('');
const optionsComputed = computed(() =>
  (options:any[]) =>
    // 为了过滤出选项，并将到的转换为html字符串，此时我们要用sdm2的filterMap函数
    filterMap(options, query.value, {
      // 忽略大小写
      ignoreCase: true,
      // 把matchStr返回的字符串作为被匹配项
      matchStr: ({label}:any) => label,
      // 匹配到后转换为html高亮字符串
      onMatched: (matchedStr:string) => `<span style="color: red">${matchedStr}</span>`,
      // 将匹配到的项转换转换为需要的格式，str为onMatched转换后的字符串，origin为数组的每项原始值
      onMap: ({str, origin}:any) => {
        return {
          highlight: str,
          ...origin
        }
      }
    })
)

const emits = defineEmits(['search'])
const handleSearch = () => {
  emits('search',formData)
}
onMounted(() => {
  getOptions()
  checkDefault()
})
defineExpose({
  checkDefault,
  formData,
  form
})
</script>

<style scoped>

</style>